#include <stdint.h>
#include <stdlib.h> //cstdlib和stdlib.h都可以
#include <stdio.h>  //cstdio和stdio.h都可以
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>

char *http_1 = "POST /MediaRenderer/%s/Control HTTP/1.1\r\n";
char *http_2 = "Host: %s:%s\r\n";
char *http_3 = "User-Agent: python-requests/2.27.1\r\n";
char *http_4 = "Accept-Encoding: gzip, deflate\r\n";
char *http_5 = "Accept: */*\r\n";
char *http_6 = "Connection: keep-alive\r\n";
char *http_7 = "Content-Type: text/xml; charset=\"utf-8\"\r\n";
char *http_8 = "SOAPACTION: urn:schemas-upnp-org:service:%s:1#%s\r\n";
char *http_9 = "Content-Length: %d\r\n";
char *http_10 = "\r\n";

char *soap_play = "<?xml version=\"1.0\" encoding=\"utf-8\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:Play xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>0</InstanceID><Speed>1</Speed></u:Play></s:Body></s:Envelope>";
char *soap_vol = "<?xml version=\"1.0\" ?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:SetVolume xmlns:u=\"urn:schemas-upnp-org:service:RenderingControl:1\"><InstanceID>0</InstanceID><Channel>Master</Channel><DesiredVolume>%d</DesiredVolume></u:SetVolume></s:Body></s:Envelope>";

int clientSocket;
char *sonos_ip = "192.168.0.241";
char *sonos_port = "1400";

void sonos_discor();
int create_tcp_client()
{
    // 1 创建socket 参数一: 协议类型(版本) 参数二: 通信媒介 参数三: 保护方式
    clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == clientSocket)
        printf("创建socket失败:%m\n"), exit(-1);
    printf("创建socket成功!\n");

    // 2. 创建服务器协议地址簇
    struct sockaddr_in cAddr = {0};
    cAddr.sin_family = AF_INET;
    cAddr.sin_addr.s_addr = inet_addr("192.168.0.241"); //将字符串转整数
    cAddr.sin_port = htons(atoi("1400"));               //将字符串转整数,再将小端转换成大端

    // 3.连接服务器
    int r = connect(clientSocket, (struct sockaddr *)&cAddr, sizeof cAddr);
    if (-1 == r)
        printf("连接服务器失败:%m\n"), close(clientSocket), exit(-2);
    printf("连接服务器成功!\n");
}

void size_test()
{
    int size = 0;

    size = strlen(http_1);
    printf("size %d \n", size);

    size = size + strlen(http_2);
    printf("size %d \n", size);

    size = size + strlen(http_3);
    printf("size %d \n", size);

    size = size + strlen(http_4);
    printf("size %d \n", size);

    size = size + strlen(http_5);
    printf("size %d \n", size);

    size = size + strlen(http_6);
    printf("size %d \n", size);

    size = size + strlen(http_7);
    printf("size %d \n", size);

    size = size + strlen(http_8);
    printf("size %d \n", size);

    size = size + strlen(http_9);
    printf("size %d \n", size);

    size = size + strlen(http_10);
    printf("size %d \n", size);

    printf("soap %d \n", strlen(soap_play));
}

void http_head_send(char *upnpMessageType, char *ip, char *port, char *action, int16_t content_len)
{
    char buf[200];
    int size;

    memset(buf, 0, sizeof(buf));
    sprintf(buf, http_1, upnpMessageType);
    size = send(clientSocket, buf, strlen(buf), 0);

    memset(buf, 0, sizeof(buf));
    sprintf(buf, http_2, ip, port);
    size = send(clientSocket, buf, strlen(buf), 0);
    printf("%s\n", buf);

    size = send(clientSocket, http_3, strlen(http_3), 0);

    size = send(clientSocket, http_4, strlen(http_4), 0);

    size = send(clientSocket, http_5, strlen(http_5), 0);

    size = send(clientSocket, http_6, strlen(http_6), 0);

    size = send(clientSocket, http_7, strlen(http_7), 0);

    memset(buf, 0, sizeof(buf));
    sprintf(buf, http_8, upnpMessageType, action);
    size = send(clientSocket, buf, strlen(buf), 0);

    memset(buf, 0, sizeof(buf));
    sprintf(buf, http_9, content_len);
    size = send(clientSocket, buf, strlen(buf), 0);
    printf("%s\n", buf);

    size = send(clientSocket, http_10, strlen(http_10), 0);
}

void sonos_play()
{
    http_head_send("AVTransport", sonos_ip, sonos_port, "Play", strlen(soap_play));
    send(clientSocket, soap_play, strlen(soap_play), 0);
}

void sonos_set_vol(uint8_t value)
{
    char *buf = NULL;

    buf = malloc(1200);
    if (buf == NULL)
    {
        printf("error \n");
        goto end;
    }
    memset(buf, 0, sizeof(buf));
    sprintf(buf, soap_vol, value);
    http_head_send("RenderingControl", sonos_ip, sonos_port, "SetVolume", strlen(buf));

    send(clientSocket, buf, strlen(buf), 0);
    printf("%s\n", buf);

end:
    if (buf)
    {
        free(buf);
    }

    return;
}

int main()
{
    create_tcp_client();
    sonos_set_vol(20);
    // sleep(2);
    // close(clientSocket);

    // create_tcp_client();
    // sonos_play();
    // sleep(2);
    // close(clientSocket);
    // sonos_discor();
    while (1)
    {
        sleep(1);
    }

    return 0;
}

#define DISCOVERY_IP "239.255.255.250"
#define DISCOVERY_PORT "1900"
#define DISCOVERY_HTTP_FRAME "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: ssdp:discover\r\nMX: 1\r\nST: urn:schemas-upnp-org:device:ZonePlayer:1"

void sonos_discor()
{
    int s_fd;
    char buf[1200];
    s_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == s_fd)
    {
        perror("socket");
        return 1;
    }
    struct sockaddr_in server;

    server.sin_family = AF_INET;
    server.sin_port = htons(1900);
    inet_pton(AF_INET, DISCOVERY_IP, &server.sin_addr);

    sendto(s_fd, DISCOVERY_HTTP_FRAME, strlen(DISCOVERY_HTTP_FRAME), 0, (struct sockaddr *)&server, sizeof(server));

    bzero(buf, sizeof(buf));
    int r = recvfrom(s_fd, buf, sizeof(buf), 0, NULL, NULL);
    printf("biuf %s\n", buf);
    close(s_fd);
    return 0;
}
